﻿using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using Basmus.Util;

namespace Basmus.Resources
{
    public class StandartVirtualPathService : IVirtualPathService
    {
        private readonly ReaderWriterCache<Type, string> _cache = new ReaderWriterCache<Type, string>();

        private readonly IVirtualPathService _virtualPathAttributeService;
        private readonly IEnumerable<IPathResolver> _pathResolvers;
        private readonly IFullNameResolver _fullNameAttributeResolver;
        private readonly INameResolver _typeNameResolver;
        private readonly IExtensionResolver _extensionAttributeResolver;

        private readonly bool _backslashed;
        private readonly bool _replaceSlash;

        private static PathPartsResolvers GetDefaultResolvers(bool backslashed, NamespaceMap namespaceMap)
        {
            return new PathPartsResolvers
                {
                    FullPathResolver = new VirtualPathAttributeService(),
                    BasePathResolvers = new IPathResolver[]
                                            {
                                                new PathAttributeResolver(), 
                                                new NamespacePathResolver(backslashed, namespaceMap)
                                            },
                    FullNameResolver = new FullNameAttributeResolver(),
                    NameWithoutExtensionResolver = new TypeNameResolver(),
                    ExtensionResolver = new ExtensionAttributeResolver()
                };
        }

        public StandartVirtualPathService(bool backslashed, NamespaceMap namespaceMap, bool replaceSlash)
            :this(GetDefaultResolvers(backslashed, namespaceMap), backslashed, replaceSlash)
        {
            
        }

        protected StandartVirtualPathService(PathPartsResolvers resolvers, bool backslashed, bool replaceSlash)
        {
            _backslashed = backslashed;
            _replaceSlash = replaceSlash;
            _virtualPathAttributeService = resolvers.FullPathResolver;
            _pathResolvers = new List<IPathResolver>(resolvers.BasePathResolvers);
            _fullNameAttributeResolver = resolvers.FullNameResolver;
            _typeNameResolver = resolvers.NameWithoutExtensionResolver;
            _extensionAttributeResolver = resolvers.ExtensionResolver;
        }

        public string Resolve(Type type)
        {
            var result = _cache.FetchOrCreateItem(type, () => BuildFullPath(type));
            return result;
        }

        private string BuildFullPath(Type type)
        {
            var fullPath = _virtualPathAttributeService.Resolve(type);
            if (fullPath != null)
                return ReplaceSlash(fullPath).TrimEnd('\\', '/');
            var path = _pathResolvers.Select(x => x.Resolve(type)).FirstOrDefault(x => x != null);
            if (path == null)
                return null;
            var fullName = _fullNameAttributeResolver.Resolve(type);
            if (fullName != null)
                return ReplaceSlash(path).TrimEnd('\\', '/') + GetSlash() + fullName;
            var name = _typeNameResolver.Resolve(type);
            var extension = _extensionAttributeResolver.Resolve(type) ?? string.Empty;
            return ReplaceSlash(path).TrimEnd('\\', '/') + GetSlash() + name + extension;
        }

        private string ReplaceSlash(string source)
        {
            if (_replaceSlash)
            {
                return _backslashed ? source.Replace('/', '\\') : source.Replace('\\', '/');
            }
            return source;
        }

        private string GetSlash()
        {
            return _backslashed ? "\\" : "/";
        }
    }
}
